#include "action.h"
#include "../../base/logger.h"
#include "../../vmath/scalar.h"
#include <cstdarg>

OPEN_JLIB_NS


void ImmediateAction::start () {
  _updated = false;
}
bool ImmediateAction::done () const {
  return _updated;
}
f32 ImmediateAction::update (f32 dt) {
  _updated = true;
  apply();
  return dt;
}


void ContinuedAction::start () {
  _elapsed = 0.0F;
}
bool ContinuedAction::done () const {
  return _elapsed >= _duration;
}
f32 ContinuedAction::update (f32 dt) {
  _elapsed += dt;
  auto p = scalar_min(_elapsed / _duration, 1.0F);
  if (_mapper)
    p = _mapper(p);
  apply(p);
  return scalar_max(_elapsed - _duration, 0.0F);
}
bool ContinuedAction::init (f32 duration) {
  _duration = duration;
  return duration > 0.0F;
}


void SeriesAction::start () {
  _init = 0;
  _done = 0;
}
bool SeriesAction::done () const {
  return _done >= _queue.size();
}
f32 SeriesAction::update (f32 dt) {
  for (auto size = _queue.size(); _done < size; ++_done) {
    if (_init == _done)
      _queue[_init++]->start();
    auto &action = _queue[_done];
    dt = action->update(dt);
    if (!action->done())
      break;
  }
  return dt;
}
bool SeriesAction::init (Action* a, ...) {
  debug_assert(a);
  _queue.emplace_back(a);
  va_list ap;
  va_start(ap, a);
  for (auto action = va_arg(ap, Action*); action; action = va_arg(ap, Action*))
    _queue.emplace_back(action);
  return true;
}
bool SeriesAction::init (const std::vector<Ptr<Action>> &actions) {
  for (auto &action : actions) {
    debug_assert(action);
    _queue.emplace_back(action);
  }
  return true;
}


void ParallelAction::start () {
  for (auto &action : _queue)
    action->start();
  _done = 0;
}
bool ParallelAction::done () const {
  return _done >= _queue.size();
}
f32 ParallelAction::update (f32 dt) {
  auto rt = dt;
  for (auto &action : _queue) {
    if (action->done())
      continue;
    auto t = action->update(dt);
    if (action->done())
      ++_done;
    rt = scalar_min(t, rt);
  }
  return rt;
}
bool ParallelAction::init (Action* a, ...) {
  debug_assert(a);
  _queue.emplace_back(a);
  va_list ap;
  va_start(ap, a);
  for (auto action = va_arg(ap, Action*); action; action = va_arg(ap, Action*))
    _queue.emplace_back(action);
  return true;
}
bool ParallelAction::init (const std::vector<Ptr<Action>> &actions) {
  for (auto action : actions) {
    debug_assert(action);
    _queue.emplace_back(action);
  }
  return true;
}


void RepeatAction::start () {
  _action->start();
  _round = 0;
}
bool RepeatAction::done () const {
  return _round >= _loops;
}
f32 RepeatAction::update (f32 dt) {
  auto &action = _action;
  while (dt > 0.0F && _round < _loops) {
    dt = action->update(dt);
    if (action->done()) {
      ++_round;
      action->start();
    }
  }
  return dt;
}
bool RepeatAction::init (Action* action, int times) {
  debug_assert(action);
  _action = action;
  _loops = (u32)times;
}


CLOSE_JLIB_NS

